# frozen_string_literal: true

require_relative '../../../../../spec_helper'
require 'wpxf/modules'

describe Wpxf::Auxiliary::WpMarketplaceV24FileDownload do
  let(:subject) { described_class.new }
  let(:post_res) { Wpxf::Net::HttpResponse.new(nil) }
  let(:session_cookie) { double('cookie') }

  before :each, 'setup subject' do
    allow(subject).to receive(:check_plugin_version_from_changelog)
    allow(subject).to receive(:emit_error)
    allow(subject).to receive(:emit_info)
    allow(subject).to receive(:execute_post_request).and_return(post_res)
    allow(subject).to receive(:session_cookie).and_return(session_cookie)
    allow(subject).to receive(:fetch_ajax_nonce).and_call_original
  end

  it 'should return a Wpxf::Module' do
    expect(subject).to be_a Wpxf::Module
  end

  it 'should check the plugin version is < 2.4.1' do
    subject.check
    expect(subject).to have_received(:check_plugin_version_from_changelog)
      .with('wpmarketplace', 'readme.txt', '2.4.1')
      .exactly(1).times
  end

  it 'should require authentication' do
    expect(subject.requires_authentication).to be true
  end

  it 'should configure the default remote file path' do
    expected = '../../../wp-config.php'
    expect(subject.default_remote_file_path).to eql expected
  end

  it 'should configure the working directory' do
    expected = 'wp-content/plugins/wpmarketplace'
    expect(subject.working_directory).to eql expected
  end

  it 'should make a POST request to start the download' do
    expect(subject.download_request_method).to eql :post
  end

  it 'should configure the downloader url' do
    expect(subject.downloader_url).to eql subject.full_uri
  end

  describe 'before the download begins' do
    it 'should attempt to modify the plugin permissions' do
      subject.before_download
      expect(subject).to have_received(:execute_post_request)
        .with(
          url: subject.full_uri,
          body: {
            'action' => 'wpmp_pp_ajax_call',
            'execute' => 'wpmp_save_settings',
            '_wpmp_settings[user_role][]' => 'subscriber'
          },
          cookie: session_cookie
        )
    end

    context 'if the plugin permissions cannot be changed' do
      it 'should emit an error' do
        post_res.code = 404
        subject.before_download
        expect(subject).to have_received(:emit_error)
          .with('Failed to modify the plugin permissions')
          .exactly(1).times
      end

      it 'should fail the module execution' do
        post_res.code = 404
        res = subject.before_download
        expect(res).to be false
      end
    end

    context 'if the plugin permissions are successfully changed' do
      before :each, 'setup mock' do
        post_res.code = 200
        post_res.body = 'Settings Saved Successfully'
      end

      it 'should emit a verbose info message' do
        subject.before_download
        expect(subject).to have_received(:emit_info)
          .with('Modified plugin permissions successfully', true)
          .exactly(1).times
      end

      it 'should attempt to acquire an AJAX nonce' do
        subject.before_download
        expect(subject).to have_received(:fetch_ajax_nonce)
      end
    end

    context 'if an AJAX nonce cannot be acquired' do
      before :each, 'setup stub responses' do
        plugin_modification_res = Wpxf::Net::HttpResponse.new(nil)
        nonce_res = Wpxf::Net::HttpResponse.new(nil)

        plugin_modification_res.code = 200
        plugin_modification_res.body = 'Settings Saved Successfully'

        nonce_res.code = 404

        allow(subject).to receive(:execute_post_request)
          .and_return(plugin_modification_res, nonce_res)
      end

      it 'should emit an error' do
        post_res.code = 404
        subject.before_download
        expect(subject).to have_received(:emit_error)
          .with('Failed to acquire a download nonce')
          .exactly(1).times
      end

      it 'should fail the module execution' do
        res = subject.before_download
        expect(res).to be false
      end
    end

    context 'if an AJAX nonce is acquired' do
      before :each, 'setup stub responses' do
        plugin_modification_res = Wpxf::Net::HttpResponse.new(nil)
        nonce_res = Wpxf::Net::HttpResponse.new(nil)

        plugin_modification_res.code = 200
        plugin_modification_res.body = 'Settings Saved Successfully'

        nonce_res.code = 200
        nonce_res.body = '<input name="__product_wpmp" value="nonce_value">'

        allow(subject).to receive(:execute_post_request)
          .and_return(plugin_modification_res, nonce_res)
      end

      it 'should emit a verbose info message containing the nonce' do
        subject.before_download
        expect(subject).to have_received(:emit_info)
          .with('Acquired nonce "nonce_value"', true)
          .exactly(1).times
      end

      it 'should attempt to create a product that exposes the target file' do
        allow(subject).to receive(:create_product).and_call_original
        subject.before_download
        expect(subject).to have_received(:create_product)
      end

      it 'should create a random download ID to be used in the download request parameters' do
        subject.before_download
        expect(subject.download_id).to match(/1[0-9]{5}/)
        expect(subject.download_request_params).to eql('wpmpfile' => subject.download_id)
      end
    end

    context 'if the product creation fails' do
      before :each, 'setup stub responses' do
        plugin_modification_res = Wpxf::Net::HttpResponse.new(nil)
        nonce_res = Wpxf::Net::HttpResponse.new(nil)
        product_res = Wpxf::Net::HttpResponse.new(nil)

        plugin_modification_res.code = 200
        plugin_modification_res.body = 'Settings Saved Successfully'

        nonce_res.code = 200
        nonce_res.body = '<input name="__product_wpmp" value="nonce_value">'

        product_res.code = 404

        allow(subject).to receive(:execute_post_request)
          .and_return(
            plugin_modification_res,
            nonce_res,
            product_res
          )
      end

      it 'should emit an error' do
        subject.before_download
        expect(subject).to have_received(:emit_error)
          .with('Failed to create dummy product')
          .exactly(1).times
      end

      it 'should fail the module execution' do
        res = subject.before_download
        expect(res).to be false
      end
    end

    context 'if the product is crated' do
      before :each, 'setup stub responses' do
        plugin_modification_res = Wpxf::Net::HttpResponse.new(nil)
        nonce_res = Wpxf::Net::HttpResponse.new(nil)
        product_res = Wpxf::Net::HttpResponse.new(nil)

        plugin_modification_res.code = 200
        plugin_modification_res.body = 'Settings Saved Successfully'

        nonce_res.code = 200
        nonce_res.body = '<input name="__product_wpmp" value="nonce_value">'

        product_res.code = 200

        allow(subject).to receive(:execute_post_request)
          .and_return(
            plugin_modification_res,
            nonce_res,
            product_res
          )
      end

      it 'should pass the pre-download checks' do
        res = subject.before_download
        expect(res).to be true
      end
    end
  end
end
